<?php

namespace App\Package\Tree;

use Illuminate\Support\Collection;
use App\Exceptions\GeneralException;

/**
 * 生成树形结构类
 *
 * Date: 23/03/2018
 * @author George
 * @package App\Package\Tree
 */
class Tree
{
	/**
	 * 生成的树
	 *
	 * @var
	 * Date: 22/03/2018
	 * @author George
	 */
	protected $tree;

	/**
	 * 暂存区
	 *
	 * @var Collection
	 * Date: 22/03/2018
	 * @author George
	 */
	protected $collection;

	/**
	 * 定义主键名称
	 *
	 * @var string
	 * Date: 22/03/2018
	 * @author George
	 */
	private $primaryKey = 'id';

	/**
	 * 定义父键名称
	 *
	 * @var string
	 * Date: 22/03/2018
	 * @author George
	 */
	private $parentKey = 'parent_id';

	/**
	 * 定义子键名称
	 *
	 * @var string
	 * Date: 22/03/2018
	 * @author George
	 */
	private $childrenKey = 'children';

	/**
	 * 设置主键名称
	 *
	 * Date: 22/03/2018
	 * @author George
	 * @param string $primaryKey
	 * @return $this|mixed
	 */
	public function setPrimaryKey(string $primaryKey = 'id')
	{
		$this->primaryKey = $primaryKey;
		return $this;
	}

	/**
	 * 设置父键名称
	 *
	 * Date: 22/03/2018
	 * @author George
	 * @param string $parentKey
	 * @return $this|mixed
	 */
	public function setParentKey(string $parentKey = 'parent_id')
	{
		$this->parentKey = $parentKey;
		return $this;
	}

	/**
	 * 设置子键名称
	 *
	 * Date: 22/03/2018
	 * @author George
	 * @param string $childrenKey
	 * @return $this|mixed
	 */
	public function setChildrenKey(string $childrenKey = 'children')
	{
		$this->childrenKey = $childrenKey;
		return $this;
	}

	/**
	 * 生成树结构
	 *
	 * Date: 23/03/2018
	 * @author George
	 * @param $collection
	 * @param string $primaryKey
	 * @param string $parentKey
	 * @param string $childrenKey
	 * @param string $topvalue
	 * @return Collection
	 * @throws GeneralException
	 */
	public function make($collection, string $primaryKey = 'id', string $parentKey = 'parent_id', string $childrenKey = 'children', string $topvalue = "")
	{
		$collection = $this->transform($collection);

		$this->setPrimaryKey($primaryKey);
		$this->setParentKey($parentKey);
		$this->setChildrenKey($childrenKey);

		$this->collection = $collection->groupBy($this->parentKey);
		$this->tree = $this->collection->pull($topvalue);

		if (count($this->tree) < 1) {
			return $collection;
		}

		if (count($this->collection) > 0) {
			foreach ($this->tree as $item) {
				$this->recursion($item);
			}
		}

		return $this->tree;
	}

	/**
	 * 递归生成树结构
	 *
	 * Date: 22/03/2018
	 * @author George
	 * @param $item
	 */
	private function recursion($item)
	{
		if ($this->collection->has($item->{$this->primaryKey})) {
			$item->{$this->childrenKey} = $this->collection->pull($item->{$this->primaryKey});
			foreach ($item->{$this->childrenKey} as $object) {
				$this->recursion($object);
			}
		}
	}

	/**
	 * 转换数据类型
	 *
	 * Date: 22/03/2018
	 * @author George
	 * @param $collection
	 * @return Collection
	 * @throws GeneralException
	 */
	private function transform($collection)
	{
		if ($collection instanceof Collection) {
			return $collection;
		}

		if (is_array($collection)) {
			return collect($collection);
		}

		throw new GeneralException('只支持数组和集合数据类型', 400);
	}
}
